﻿using System;
using UnityEngine;

namespace Mars.MeshUI
{
    public enum MeshCanvasDirtyFlag
    {
        kNone = 0,
        kPosition = 1 << 0,
        kColor = 1 << 1,
        kUv = 1 << 2,
        kVisible = 1 << 3,
        kAll = kPosition | kColor | kUv,
    }

    [RequireComponent(typeof(MeshRenderer))]
    [RequireComponent(typeof(MeshFilter))]
    public class MeshCanvas : MonoBehaviour
    {
        public static int mainTextureID;
        public static int tintColorID;
        public bool useVertexColor = false;
        public bool useMaterialCopy = false;
        public int depth = -1;
        private float m_Alpha;
        public Renderer render = default;
        public MeshFilter filter = default;
        private VertexHelperEx vertexHelper;
        private CustomUIGraphic[] childs;
        private Texture m_MainTexture;
        private MaterialPropertyBlock block;
        private Color m_TintColor = Color.white;
        private Transform m_Transform;


        public enum InstanceDirtyFlag
        {
            none = 0,
            color = 1 << 0,
            uv = 1 << 1,
            fill = 1 << 2,
            visible = 1 << 3,
            position = 1 << 4,

            Para = fill | visible | color | position,
            UV = uv,
            Color = color,
            all = Para | UV | Color,
        }


        private bool isEnable;


        public float alpha
        {
            get { return m_Alpha; }

            set
            {
                float v = Mathf.Clamp01(value);

                if (Math.Abs(m_Alpha - v) < 0.0001f)
                {
                    return;
                }

                m_Alpha = v;
                SetAlpha(m_Alpha);
            }
        }

        public Texture mainTexture
        {
            get { return m_MainTexture; }

            set
            {
                if (render == null || render.sharedMaterial == null)
                {
                    return;
                }

                m_MainTexture = value;

                SetMaterialTexture();
            }
        }

        public int UILayer { get; set; }

        // Use this for initialization
        void Awake()
        {
            UILayer = 5; //unity默认layer=5是ui层
            SetEnable(true);

            if (mainTextureID == 0)
            {
                mainTextureID = MaterialPropertyHelper.Instance.GetPropertyID("_MainTex");
                tintColorID = MaterialPropertyHelper.Instance.GetPropertyID("_Color");
            }

            if (render == null)
            {
                render = GetComponent<MeshRenderer>();
            }

            if (filter == null)
            {
                filter = GetComponent<MeshFilter>();
            }

            filter.mesh = new Mesh();

            if (block == null && render != null)
            {
                block = new MaterialPropertyBlock();
                render.GetPropertyBlock(block);
            }

            childs = GetComponentsInChildren<CustomUIGraphic>(true);

            vertexHelper = new VertexHelperEx(filter.mesh, childs.Length, useVertexColor);

            for (int i = 0; i < childs.Length; i++)
            {
                var child = childs[i];
                if (child != null)
                {
                    child.MeshCanvasIndex = i;
                    child.Init(this);
                    vertexHelper.SetVertexDataById(child.VerticesData, child.IndicType, i);
                }
            }

            vertexHelper.FillMeshById(filter.mesh);

            m_Transform = transform;
        }

        public void SetSort(int sort, bool releativeParent = false)
        {
            if (releativeParent)
            {
                var parent = GetComponentInParent<Renderer>();

                if (parent != null)
                {
                    render.sortingOrder = parent.sortingOrder + sort;
                    return;
                }
            }

            render.sortingOrder = sort;

            SetDepth();
        }

        private void SetAlpha(float v)
        {
            if (block == null)
            {
                return;
            }

            m_TintColor.a = v;
            block.SetColor(tintColorID, m_TintColor);
            render.SetPropertyBlock(block);
        }

        void SetMaterialTexture()
        {
            block.SetTexture(mainTextureID, mainTexture);
            render.SetPropertyBlock(block);
        }

        public void SetEnable(bool isEnable)
        {
            gameObject.layer = isEnable ? UILayer : -1000;
        }

        void OnEnable()
        {
            SetDepth();
        }


        void SetDepth()
        {
            if (null == m_Transform)
            {
                Debug.LogError("[MeshCanvas.SetDepth] not Awaked");
                return;
            }

            //depth = m_Transform.GetSiblingIndex();
            var pos = m_Transform.localPosition;
            pos.z = -depth * 0.1f;
            m_Transform.localPosition = pos;
        }

        public void SetFlagDirtyById(int id, MeshCanvasDirtyFlag flag)
        {
            if (vertexHelper == null)
            {
                return;
            }

            vertexHelper.SetDirtyById(id, flag);
        }

        public void SetVisibleDirtyById(int id, bool visible)
        {
            if (vertexHelper == null)
            {
                return;
            }

            vertexHelper.SetVisibleDirtyById(id, visible);
        }

        public void SetVertexDataById(int id, VertexData[] datas, VertexHelperEx.VertexIndicType type)
        {
            if (vertexHelper == null)
            {
                return;
            }

            vertexHelper.SetVertexDataById(datas, type, id);
        }

        public void SetVertexLenghtDirtyById(int id, int length)
        {
            if (vertexHelper == null)
                return;
            vertexHelper.SetVertexLenghtDirtyById(id, length);
        }


        public void LateUpdate()
        {
            if (render.isVisible == false)
                return;

            ReBuild();
        }


        public void ReBuild()
        {
            if (vertexHelper == null)
                return;
            if (childs == null)
                return;
            for (int i = 0; i < childs.Length; i++)
            {
                childs[i].Rebuild();
            }

            vertexHelper.FillMeshById(filter.mesh);
        }

        void OnDestroy()
        {
            if (vertexHelper != null)
            {
                vertexHelper.Dispose();
            }
        }
    }

    [System.Serializable]
    public struct VertexData
    {
        public Vector3 position;
        public Vector4 uv;
        public Color32 color;
    }
}